package com.company.nuwa.mybatis.generator.plugins;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.PropertyRegistry;
import org.mybatis.generator.internal.util.StringUtility;

import java.text.MessageFormat;
import java.util.Properties;

/**
 * <p>Facade</p>
 *
 * @author lili
 * @version 1.0: FacadePlugin
 * @date 2023/9/18 17:36
 */
public class FacadePlugin {
    public static GeneratedJavaFile facadeFile(IntrospectedTable introspectedTable,
                                               Context context,
                                               String targetProject) {
        Properties contextProperties = context.getProperties();
        String applicationName = contextProperties.getProperty("applicationName");
        String contextPath = contextProperties.getProperty("contextPath");
        String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
        StringBuilder builder = new StringBuilder();
        FullyQualifiedJavaType mapperType = new FullyQualifiedJavaType(
            introspectedTable.getMyBatis3JavaMapperType());
        /*  TopLevelClass requestClass = new TopLevelClass(builder.delete(0, builder.length())
            .append(mapperType.getPackageName().replace(".mapper", "").replace("domain", "api"))
            .append(".").append(domainObjectName).append("Facade").toString());*/
        Interface requestClass = new Interface(builder.delete(0, builder.length())
            .append(mapperType.getPackageName().replace(".mapper", "").replace("domain", "api"))
            .append(".").append(domainObjectName).append("Facade").toString());
        requestClass.setVisibility(JavaVisibility.PUBLIC);
        context.getCommentGenerator().addJavaFileComment(requestClass);
        String basePage = mapperType.getPackageName();
        //添加domain的import
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".api",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".request",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".dto",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".api",".hystrix.*")));
        //添加domain的import
        requestClass.addImportedType(
            new FullyQualifiedJavaType("com.company.nuwa.common.domain.HttpMessageResult"));
        requestClass.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageInfo"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("com.company.beauty.feign.config.FeignConfiguration"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("org.springframework.cloud.openfeign.FeignClient"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType(("org.springframework.validation.annotation.Validated")));
        requestClass.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("org.springframework.web.bind.annotation.PostMapping"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("org.springframework.web.bind.annotation.GetMapping"));
        requestClass.addImportedType(
            new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestParam"));
        requestClass.addImportedType(new FullyQualifiedJavaType("javax.annotation.Generated"));
        //添加Feign的注解
        String feignAnnotation = MessageFormat.format(
            "@FeignClient(value = \"{0}\", path = \"/{1}\",url = \"{2}\", configuration = FeignConfiguration.class, contextId = \"{3}FeignClient\", fallbackFactory ={4}FeignClientHystrix.class)",
            applicationName, contextPath,"${zk_openapi_url:}", domainObjectName, domainObjectName);
        requestClass.addAnnotation(feignAnnotation);
        requestClass.addJavaDocLine("/**");
        String remarks = introspectedTable.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            String[] remarkLines = remarks.split(System.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                requestClass.addJavaDocLine(" * <p>" + remarkLine + "</p>");
            }
        }

        StringBuilder sb = new StringBuilder();
        sb.append(" * @author ").append(System.getProperties().getProperty("user.name"));
        requestClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        sb.append(" * ").append("@version 1.0:")
            .append(introspectedTable.getFullyQualifiedTable().getDomainObjectName())
            .append("Facade").append(".java");
        requestClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        sb.append(" * @date ");
        sb.append(ApiExtPluginUtils.getDateString());
        requestClass.addJavaDocLine(sb.toString());
        requestClass.addJavaDocLine(" */");
        //增加方法
        addMethod(domainObjectName, requestClass);
        updateMethod(domainObjectName, requestClass);
        selectMethod(domainObjectName, requestClass);
        selectByIdsMethod(domainObjectName, requestClass);
        deleteMethod(domainObjectName, requestClass);
        enableMethod(domainObjectName, requestClass);
        selectPageMethod(domainObjectName, requestClass);
        GeneratedJavaFile generatedJavaFile = new GeneratedJavaFile(requestClass,
            targetProject,
            context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
            context.getJavaFormatter());
        return generatedJavaFile;
    }

    //hystrix
    public static void addMethod(String domainObjectName, Interface requestClass) {
        /**
         * add方法
         *  @PostMapping("/api/{domainObjectName}/add")
         *  HttpMessageResult<Boolean> add(@RequestBody @Validated DomainAddRequest request);
         */
        Method method = new Method("add");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType("HttpMessageResult<Boolean>"));
        method.setAbstract(true);
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 新增");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine("* @return Boolean");
        method.addJavaDocLine(" */");
        String addAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/add\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(addAnnotationName);
        Parameter addParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "AddRequest"), "request");
        addParameter.addAnnotation("@RequestBody @Validated");
        method.addParameter(addParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void updateMethod(String domainObjectName, Interface requestClass) {
        /**
         * update方法
         *  @PostMapping("/api/{domainObjectName}/update")
         *  HttpMessageResult<Boolean> update(@RequestBody @Validated DomainUpdateRequest request);
         */
        Method method = new Method("update");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setAbstract(true);
        method.setReturnType(new FullyQualifiedJavaType("HttpMessageResult<Boolean>"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 更新");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine("* @return Boolean");
        method.addJavaDocLine(" */");
        String updateAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/update\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(updateAnnotationName);
        Parameter updatedParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "UpdateRequest"), "request");
        updatedParameter.addAnnotation("@RequestBody @Validated");
        method.addParameter(updatedParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectMethod(String domainObjectName, Interface requestClass) {
        /*
         * DomainDTO selectById(Long id);
         * */
        Method method = new Method("selectById");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setAbstract(true);
        method.setReturnType(new FullyQualifiedJavaType(
            MessageFormat.format("HttpMessageResult<{0}DTO>", domainObjectName)));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 单条记录查询");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine(
            "* @return " + MessageFormat.format("HttpMessageResult<{0}DTO>", domainObjectName));
        method.addJavaDocLine(" */");
        String selectAnnotationName = MessageFormat.format("@GetMapping(\"/api/{0}/selectById\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(selectAnnotationName);
        Parameter selectdParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        selectdParameter.addAnnotation("@RequestParam(value = \"id\")");
        method.addParameter(selectdParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectByIdsMethod(String domainObjectName, Interface requestClass) {
        /*
         * DomainDTO selectById(Long id);
         * */
        Method method = new Method("selectByIds");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setAbstract(true);
        method.setReturnType(new FullyQualifiedJavaType(
            MessageFormat.format("HttpMessageResult<List<{0}DTO>>", domainObjectName)));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 批量查询");
        method.addJavaDocLine("* @param request 主键");
        method.addJavaDocLine("* @return " + MessageFormat.format("HttpMessageResult<List<{0}DTO>>",
            domainObjectName));
        method.addJavaDocLine(" */");
        String addAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/selectByIds\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(addAnnotationName);
        Parameter addParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "SelectByIdsRequest"), "request");
        addParameter.addAnnotation("@RequestBody @Validated");
        method.addParameter(addParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void deleteMethod(String domainObjectName, Interface requestClass) {
        /**
         * deleteById
         */
        Method method = new Method("deleteById");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setAbstract(true);
        method.setReturnType(new FullyQualifiedJavaType("HttpMessageResult<Boolean>"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 单条记录删除");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine("* @return  HttpMessageResult<Boolean>");
        method.addJavaDocLine(" */");
        String deleteAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/deleteById\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(deleteAnnotationName);
        Parameter deleteParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        deleteParameter.addAnnotation("@RequestParam(value = \"id\")");
        method.addParameter(deleteParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void enableMethod(String domainObjectName, Interface requestClass) {
        /**
         * setEnable 启用/禁用
         */
        Method method = new Method("setEnable");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setAbstract(true);
        method.setReturnType(new FullyQualifiedJavaType("HttpMessageResult<Boolean>"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 启用/禁用");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine("* @param isEnable 启用/禁用");
        method.addJavaDocLine("* @return  HttpMessageResult<Boolean>");
        method.addJavaDocLine(" */");
        String enableAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/setEnable\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(enableAnnotationName);
        Parameter enableIdParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        enableIdParameter.addAnnotation("@RequestParam(value = \"id\")");
        Parameter enableParameter = new Parameter(new FullyQualifiedJavaType("Integer"),
            "isEnable");
        enableParameter.addAnnotation("@RequestParam(value = \"isEnable\")");
        method.addParameter(enableIdParameter);
        method.addParameter(enableParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectPageMethod(String domainObjectName, Interface requestClass) {
        Method method = new Method("selectPage");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType(
            MessageFormat.format("HttpMessageResult<{0}DTO>", domainObjectName)));
        method.setAbstract(true);
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 分页查询");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine("* @return " + MessageFormat
            .format("HttpMessageResult<PageInfo<{0}DTO>>", domainObjectName));
        method.setReturnType(new FullyQualifiedJavaType(
            MessageFormat.format("HttpMessageResult<PageInfo<{0}DTO>>", domainObjectName)));
        method.addJavaDocLine(" */");
        String addAnnotationName = MessageFormat.format("@PostMapping(\"/api/{0}/selectPage\")",
            StringUtils.uncapitalize(domainObjectName));
        method.addAnnotation(addAnnotationName);
        Parameter addParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "SelectPageRequest"), "request");
        addParameter.addAnnotation("@RequestBody @Validated");
        method.addParameter(addParameter);
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }
}
